﻿Imports System.Threading
Imports System.Text.RegularExpressions

''' <summary>
''' Syntax Highlight TextBox
''' </summary>
''' <remarks>http://blogs.microsoft.co.il/blogs/tamir/archive/2006/12/14/RichTextBox-syntax-highlighting.aspx</remarks>
Public Class HilightTextBox
    Inherits RichTextBox

#Region "変数 Variables"
    Private keyWords As Regex
    Private stringMatch As New Regex("\""(.*?)\""")
    Private wordTagList As New List(Of WordTag)

    Private chrs As Char() = {".", ")", "(", "[", "]", ">", "<", ":", ";", ControlChars.Cr, ControlChars.Lf, ControlChars.Tab}
    Private specials As New List(Of Char)
#End Region

#Region "プロパティ Property"
    Friend WriteOnly Property HighlightWords As String
        Set(value As String)
            If value Is Nothing Then
                keyWords = Nothing
            Else
                keyWords = New Regex(value)
            End If
        End Set
    End Property
    Friend Property IntellisenceList As TreeNodes

#Region "テキストボックス互換用プロパティ Like Textbox Control's Property"
    Public Property MaxLines As Integer = Integer.MaxValue
    Public Property MinLines As Integer = 1

    Public Property Text As String

    Public Property SelectionStart As Integer
#End Region

#End Region

#Region "コンストラクタ New-Finalize"
    Public Sub New()
        specials.AddRange(chrs)
    End Sub
#End Region

#Region "メソッド Method"
    'Protected Overrides Sub OnRender(drawingContext As System.Windows.Media.DrawingContext)

    '    drawingContext.PushClip(New RectangleGeometry(New Rect(0, 0, Me.ActualWidth, Me.ActualHeight)))
    '    drawingContext.DrawRectangle(Brushes.White, Nothing, New Rect(0, 0, Me.ActualWidth, Me.ActualHeight))
    '    If Me.Text.Trim = "" Then Return


    '    Dim edtText = Me.Text.ToLower
    '    Dim flowDir As FlowDirection = Windows.FlowDirection.LeftToRight
    '    If Globalization.CultureInfo.CurrentCulture.TextInfo.IsRightToLeft Then
    '        flowDir = Windows.FlowDirection.RightToLeft
    '    End If
    '    Dim fmtText As New FormattedText(edtText, Globalization.CultureInfo.CurrentCulture,
    '                                      flowDir,
    '                                      New Typeface(Me.FontFamily.Source),
    '                                      Me.FontSize,
    '                                      Brushes.Black) With {.Trimming = TextTrimming.None}

    '    '既存クラスの検索
    '    'キーワードの検索
    '    If keyWords IsNot Nothing Then
    '        Tasks.Parallel.ForEach(keyWords.Matches(edtText).Cast(Of Match),
    '                       Sub(keyWordMatch As Match)
    '                           Dim st = edtText.IndexOf(keyWordMatch.ToString.ToLower)
    '                           fmtText.SetForegroundBrush(Brushes.Blue, st, keyWordMatch.ToString.Length)
    '                       End Sub)
    '    End If
    '    '文字列の検索
    '    Tasks.Parallel.ForEach(stringMatch.Matches(edtText).Cast(Of Match),
    '                   Sub(keyWordMatch As Match)
    '                       Dim st = edtText.IndexOf(keyWordMatch.ToString.ToLower)
    '                       fmtText.SetForegroundBrush(Brushes.Red, st, keyWordMatch.ToString.Length)
    '                   End Sub)

    '    drawingContext.DrawText(fmtText, New Point(Me.Margin.Left, Me.Margin.Top))
    '    MyBase.OnRender(drawingContext)

    'End Sub

    Private Sub OnTextChangedPrivate(ByVal sender As Object, ByVal e As TextChangedEventArgs)
        If Me.Document Is Nothing Then Return

        Dim docRange As New TextRange(Me.Document.ContentStart, Me.Document.ContentEnd)
        docRange.ClearAllProperties()

        Dim navigator = Me.Document.ContentStart
        Do While (navigator.CompareTo(Me.Document.ContentEnd) < 0)
            Dim context = navigator.GetPointerContext(LogicalDirection.Backward)
            If (context = TextPointerContext.ElementStart) AndAlso
                (TypeOf navigator.Parent Is Run) Then
                CheckWordsInRun(navigator.Parent)
            End If
            navigator = navigator.GetNextContextPosition(LogicalDirection.Forward)
        Loop
        FormatText()
    End Sub

    Private Sub FormatText()
        RemoveHandler Me.TextChanged, AddressOf OnTextChangedPrivate

        Tasks.Parallel.ForEach(wordTagList.ToList, Sub(target)
                                                       Dim range As New TextRange(target.StartPosition, target.EndPosition)
                                                       range.ApplyPropertyValue(TextElement.ForegroundProperty, New SolidColorBrush(Colors.Blue))
                                                   End Sub)
        wordTagList.Clear()

        AddHandler Me.TextChanged, AddressOf OnTextChangedPrivate
    End Sub

    Private Sub CheckWordsInRun(ByVal runSection As Run)
        Dim text = runSection.Text

        Dim stIndex As Integer = 0
        Dim edIndex As Integer = 0
        For index As Integer = 0 To text.Length
            If Not (Char.IsWhiteSpace(text(index)) OrElse
                     (specials.Contains(text(index)))) Then
                If (index > 0) AndAlso (Not Char.IsWhiteSpace(text(index - 1)) OrElse
                                                       specials.Contains(text(index - 1))) Then
                    edIndex = index - 1
                    Dim word = text.Substring(stIndex, edIndex - stIndex + 1)


                End If
            End If
        Next

    End Sub

#Region "内部利用クラス InPrivate Structure"
    Friend Structure WordTag
        Public StartPosition As TextPointer
        Public EndPosition As TextPointer
        Public Word As String
    End Structure
#End Region

#End Region

End Class
